#include "MODBUSTCP_MASTER.h"

MODBUSTCP_MASTER_T* MODBUSTCP_MASTER_t;
MODBUSTCP_MASTER_List_Par_t MODBUSTCP_MASTER_List_Par;

//************************************
// Method:    	CARD_WORK					modbus-485主站工作函数
// Programmer:  lww
// Time:		2019/2/24
// Returns:   	void
//************************************
void CARD_WORK(MODBUSTCP_MASTER)()
{
#define TASK_NAME_LENGTH	44
	unsigned char i;
	int j;
	NAME(MODBUSTCP_MASTER)* base;
	Net_State_t* Net_State;
	NetThread_Par_t* NetThread_ParA, * NetThread_ParB;
	pthread_t tMODBUSTCP_MASTER_RW_IDA = 0;
	pthread_t tMODBUSTCP_MASTER_RW_IDB = 0;
	char name1[TASK_NAME_LENGTH] = { 0 };
	char name2[TASK_NAME_LENGTH] = { 0 };
	char IP_Str[IP_STR_LENGTH] = { 0 };

	char *pIPpool[IOCARD_MAX_NUM]{};								//< Shike20210515 每当卡件里有一个新的IP，把新IP记录进IP池
	int IPhasfindNum = 0;											//< Shike20210515 目前遍历的卡件里已经找到的不重复IP数目
	//< 遍历所有MODBUSTCP-MASTER类型卡件   （同一从站IP在同一线程）
	for (j = 0; j < Card_List[TYPE(MODBUSTCP_MASTER)].iCount; j++)
	{
		base = (NAME(MODBUSTCP_MASTER)*)SearchAt(((List_Base_t*)Card_List[TYPE(MODBUSTCP_MASTER)].ppData[0]), j);//< Shike20210515 找到当前卡件指针
		int k = 0;
		for (; k < IPhasfindNum; k++)
		{
			if (strcmp(base->Sta.ModuleIP, pIPpool[k]) == 0)		//< duan 目前遍历到的这张卡件是否和已有的IP记录重复，重复的话直接跳过不开新线程
				break;
		}
		if (k == IPhasfindNum)										//< duan 该IP地址下存在从机。该IP地址开辟线程
		{
			pIPpool[IPhasfindNum] = base->Sta.ModuleIP;				//< Shike20210515 当前卡件是一个新的IP，指针数组记录IP，并将IPhasfindNum+1
			IPhasfindNum++;
			strcpy(IP_Str, base->Sta.ModuleIP);
			//< 初始化网口状态配置结构体
			Net_State = (Net_State_t*)calloc(1, sizeof(struct Net_State_t));
			Net_State->NetA_State = UNCONNECT;
			Net_State->NetB_State = UNCONNECT;
			Net_State->NetA_Fail_Count = 0;
			Net_State->NetB_Fail_Count = 0;

			//< 线程名称动态生成
			memset(name1, 0, TASK_NAME_LENGTH * sizeof(char));
			memset(name2, 0, TASK_NAME_LENGTH * sizeof(char));
			strcpy(name1, "tMODBUSTCP_MASTER_RW_IDA_IP");
			strcpy(name2, "tMODBUSTCP_MASTER_RW_IDB_IP");
			strcat(name1, IP_Str);
			strcat(name2, IP_Str);

			//< 启动网口A读写线程
			NetThread_ParA = (NetThread_Par_t*)calloc(1, sizeof(struct NetThread_Par_t));
			NetThread_ParA->Net_Chosen = NETA;
			strcpy(NetThread_ParA->IP_Addr, IP_Str);
			NetThread_ParA->pt = Net_State;
			THREAD_CREATE_FAILED(Thread_Create(name1, &tMODBUSTCP_MASTER_RW_IDA, NULL, SCHED_POLICY, 89, true, tMODBUSTCP_MASTER_Work_Thread, CONTROL_CORE, NetThread_ParA));
			//< 启动网口B读写线程
			/*NetThread_ParB = (NetThread_Par_t*)calloc(1, sizeof(struct NetThread_Par_t));
			NetThread_ParB->Net_Chosen = NETB;
			NetThread_ParB->IP_Addr = i;
			NetThread_ParB->pt = Net_State;
			THREAD_CREATE_FAILED(Thread_Create(name2, &tMODBUSTCP_MASTER_RW_IDB, NULL, SCHED_POLICY, 89, true, tMODBUSTCP_MASTER_Work_Thread, CONTROL_CORE, NetThread_ParB));*/
		}
	}
#undef TASK_NAME_LENGTH
}

//************************************
// Method:    	tMODBUSTCP_MASTER_Work_Thread	MODBUS-485主站工作线程
// Programmer:  lww
// Time:		2019/2/25
// Returns:   	void *
// Parameter: 	void * arg
//************************************
void *tMODBUSTCP_MASTER_Work_Thread(void* arg)
{
#define MAX_LINK_FAIL_NUM	3
#define MAX_WORK_FAIL_NUM	3
#define MODBUSTCP_EACH_COMMUNICATION_DELAY_TIME	500					//< Shike20210516 每次MODBUSTCP通讯卡件通讯间隔，延迟时间，以前没有宏定义，现在只是增加了把函数包装成宏
#define STATE	((Net_Chosen == NETA) ? (Net_State->NetA_State) : (Net_State->NetB_State))
#define OTHER_NET_STATE	((Net_Chosen == NETA) ? (Net_State->NetB_State) : (Net_State->NetA_State))
#define FAILED_COUNT	((Net_Chosen == NETA) ? (Net_State->NetA_Fail_Count) : (Net_State->NetB_Fail_Count))
#define NET_STATE_WRITE(name)	{\
	if (Net_Chosen == NETA)\
		Net_State->NetA_State = name;\
	if (Net_Chosen == NETB)\
		Net_State->NetB_State = name;\
}
#define WRITE_CARD_TIMEOUT_STATE	{\
	for (i = 0; i < Card_Num; i++)\
	{\
		base = Card_Pt_Array[i];\
		base->Base.Status |= 0x08;		/*卡件超时*/\
	}\
}
#define CANCEL_CARD_TIMEOUT_STATE	{\
	for (i = 0; i < Card_Num; i++)\
	{\
		base = Card_Pt_Array[i];\
		base->Base.Status &= 0xF7;		/*卡件取消超时*/\
	}\
}
#define WRONG_DEAL	{\
	close(sock);\
	FAILED_COUNT++;\
	if (FAILED_COUNT >= MAX_LINK_FAIL_NUM)	{ FAILED_COUNT = MAX_LINK_FAIL_NUM; }\
	if ((Net_State->NetA_Fail_Count >= MAX_LINK_FAIL_NUM) && (Net_State->NetB_Fail_Count >= MAX_LINK_FAIL_NUM))	{ WRITE_CARD_TIMEOUT_STATE; }\
	NET_STATE_WRITE(UNCONNECT);\
}

	int i, j;
	int sock;
	int Card_Num = 0;							//< 该IP下的卡件数量 （同一从站IP下的主站卡件数）
	NetThread_Par_t NetThread_Par;
	Net_Chosen_e Net_Chosen;					//< 该线程所运行网络情况 （网口选择）
	char IP_Addr[IP_STR_LENGTH];				//< IP地址 （从站的）
	Net_State_t* Net_State;						//< 网络状态
	NAME(MODBUSTCP_MASTER)* base;
	char Wrong_Sum;								//< 每张卡件通讯失败次数累加值
	bool* Card_Wrong_Flag;						//< 卡件通讯错误数组指针
	NAME(MODBUSTCP_MASTER)** Card_Pt_Array;		//< 存放卡件指针的数组的指针 （同一从站IP下的主站卡件的指针）
	char Wrong_Count = 0;						//< 通讯错误的卡件数量累加

	//< 解析传入参数
	NetThread_Par = *(NetThread_Par_t*)arg;
	Net_Chosen = NetThread_Par.Net_Chosen;
	strcpy(IP_Addr, NetThread_Par.IP_Addr);
	Net_State = NetThread_Par.pt;

	printf("the Kernel_%s is %d\r\n", "tMODBUSTCP_MASTER_Work_Thread_ID", syscall(SYS_gettid));			//< duan20200610
	//< 统计该IP下的卡件数量
	for (i = 0; i < Card_List[TYPE(MODBUSTCP_MASTER)].iCount; i++)
	{
		base = (NAME(MODBUSTCP_MASTER)*)SearchAt(((List_Base_t*)Card_List[TYPE(MODBUSTCP_MASTER)].ppData[0]), i);
		if (strcmp(base->Sta.ModuleIP ,IP_Addr) == 0)
			Card_Num++;
	}

	//< 根据该IP下的卡件数量动态开辟资源
	Card_Pt_Array = (NAME(MODBUSTCP_MASTER)**)calloc(Card_Num, sizeof(NAME(MODBUSTCP_MASTER)*));
	Card_Wrong_Flag = (bool*)calloc(Card_Num, sizeof(bool));

	//< 将该IP下卡件的指针存入到数组中
	j = 0;
	for (i = 0; i < Card_List[TYPE(MODBUSTCP_MASTER)].iCount; i++)
	{
		base = (NAME(MODBUSTCP_MASTER)*)SearchAt(((List_Base_t*)Card_List[TYPE(MODBUSTCP_MASTER)].ppData[0]), i);
		if (strcmp(base->Sta.ModuleIP, IP_Addr) == 0)
			Card_Pt_Array[j++] = base;
	}

	while (1)
	{
		if (SYS_Role != Master_Alone_Role && SYS_Role != Master_Twins_Role)//备站continue
		{	
			ExactDelay(10);
			continue;
		}
//*******************系统角色为主站才会执行以下程序***************************************************************
		if (STATE == UNCONNECT)//< 网口状态为未连接时连接网络
		{
			//if (TCP_Client_Init(&sock, 0, MODBUSTCP_MASTER_List_Par.Send_MaxTime, MODBUSTCP_MASTER_List_Par.Recv_MaxTime) == false) { WRONG_DEAL; }
			if (TCP_Client_Init(&sock, 0) == false) { WRONG_DEAL; }//TCP初始绑自己端IP和端口
			if (TCP_Client_Connect(&sock, MODBUSTCP_PORT, IP_Addr, 5) == false) { WRONG_DEAL; }//TCP连接绑对端IP和端口
			else
			{
				printf("IP = %s", IP_Addr);
				printf("connect success\r\n");
				for (i = 0; i < Card_Num; i++)
				{
					Card_Wrong_Flag[i] = false;
				}
				switch (OTHER_NET_STATE) {					//< 根据另一网口的状态，决定当前网口的状态
				case UNCONNECT:	NET_STATE_WRITE(WORK);	break;
				case WORK:		NET_STATE_WRITE(BAK);	break;
				case BAK:		NET_STATE_WRITE(WORK);	break;
				default:	break;
				}
			}				
		}

		//< 网口为备份状态时随时准备切换
		if (STATE == BAK && (OTHER_NET_STATE == UNCONNECT || OTHER_NET_STATE == BAK))
			NET_STATE_WRITE(WORK);

		//< 网口为工作状态时进行读写操作
		if (STATE == WORK)
		{
			ExactDelay(MODBUSTCP_EACH_COMMUNICATION_DELAY_TIME);					//< 延时系统基准周期 SYS_BaseTime
			for (i = 0; i < Card_Num; i++)
			{
				base = Card_Pt_Array[i];
				base->Base.Period_Count++;
				if (base->Base.Period_Count < base->Par.Card_Period) { continue; }//以此来实现定时读写
				else { base->Base.Period_Count = 0; }
				Wrong_Sum = 0;
				while (1)
				{
					if (MODBUSTCP_MASTER_RW((MODBUSTCP_MASTER_T*)base, sock)) { Card_Wrong_Flag[i] = false; break; }
					else //读写失败
					{
						Wrong_Sum++;
						if (Wrong_Sum >= MAX_WORK_FAIL_NUM) { Card_Wrong_Flag[i] = true; break; }						
					}						
				}
			}
			Wrong_Count = 0;
			for (i = 0; i < Card_Num; i++)//统计总的读写失败次数
			{
				Wrong_Count += ((Card_Wrong_Flag[i] == true) ? 1 : 0); 
			}
			if (Wrong_Count == Card_Num)//每个卡件全部读写失败
			{
				WRONG_DEAL;
			}
			else
			{
				FAILED_COUNT = 0;
				CANCEL_CARD_TIMEOUT_STATE;
			}
		}
	}
#undef MAX_LINK_FAIL_NUM
#undef MAX_WORK_FAIL_NUM
#undef MODBUSTCP_EACH_COMMUNICATION_DELAY_TIME
#undef STATE
#undef OTHER_NET_STATE
#undef FAILED_COUNT
#undef NET_STATE_WRITE
#undef WRITE_CARD_TIMEOUT_STATE
#undef CANCEL_CARD_TIMEOUT_STATE
#undef WRONG_DEAL
}

//************************************
// Method:    	MODBUSTCP_MASTER_RW				MODBUS-TCP读写函数
// Programmer:  lww
// Time:		2019/2/27
// Returns:   	bool							true-成功；false-失败
// Parameter: 	MODBUSTCP_MASTER_T * base		卡件属性结构体指针
// Parameter: 	int sock						套接字
//************************************
bool MODBUSTCP_MASTER_RW(MODBUSTCP_MASTER_T* base, int sock)
{
//函数参数
#define PARA(name)	sock, num++, base->Par.ModuleAddr, name, base->Par.StartAddrOf_##name, base->Sta.FunCodeNumOf_##name

	bool flag = false;//读写标志位，默认值失败
	static unsigned short num = 0; //报文序列号

	if (num > 60000)
		num = 0;

	if (base->Sta.FunCodeNumOf_0x01 > 0)
		flag |= MODBUSTCP_MASTER_Funcode0x01_0x02_Work(PARA(0x01), base->Base.DIChannel);
	if (base->Sta.FunCodeNumOf_0x02 > 0)
		flag |= MODBUSTCP_MASTER_Funcode0x01_0x02_Work(PARA(0x02), &(base->Base.DIChannel[base->Sta.FunCodeNumOf_0x01]));
	if (base->Sta.FunCodeNumOf_0x03 > 0)
		flag |= MODBUSTCP_MASTER_Funcode0x03_0x04_Work(PARA(0x03), base->Base.AIChannel, base->Sta.Is_Double);
	if (base->Sta.FunCodeNumOf_0x04 > 0)
		flag |= MODBUSTCP_MASTER_Funcode0x03_0x04_Work(PARA(0x04), &(base->Base.AIChannel[base->Sta.FunCodeNumOf_0x03]), base->Sta.Is_Double);
	if (base->Sta.FunCodeNumOf_0x05 > 0)
		flag |= MODBUSTCP_MASTER_Funcode0x05_Work(PARA(0x05), base->Base.DOChannel);
	if (base->Sta.FunCodeNumOf_0x06 > 0)
		flag |= MODBUSTCP_MASTER_Funcode0x06_Work(PARA(0x06), base->Base.AOChannel);
	if (base->Sta.FunCodeNumOf_0x0F > 0)
		flag |= MODBUSTCP_MASTER_Funcode0x0F_Work(PARA(0x0F), &(base->Base.DOChannel[base->Sta.FunCodeNumOf_0x05]));
	if (base->Sta.FunCodeNumOf_0x10 > 0)
		flag |= MODBUSTCP_MASTER_Funcode0x10_Work(PARA(0x10), &(base->Base.AOChannel[base->Sta.FunCodeNumOf_0x06]), base->Sta.Is_Double);

	return flag;
#undef PARA
}
/*差错处理程序*/
#define WRONG_DEAL(name)	{\
	if(name == true){\
		if (Funcode == 0x01 || Funcode == 0x02)\
			for (i = 0; i < RWNum; i++)\
				DV_Write(&(((DVChannel_t*)Ch)[i]), false, TURN_TIMEOUT);/*对该功能码对应测点做超时处理*/\
		else if (Funcode == 0x03 || Funcode == 0x04)\
			for (i = 0; i < RWNum; i++)\
				AV_Write(&(((AVChannel_t*)Ch)[i]), 0, TURN_TIMEOUT);/*对该功能码对应测点做超时处理*/\
	}\
	ExactDelay(5);\
	return false;\
}
/*报文头*/
#define MSG_HEAD	{\
	SendData[SendCount++] = HIGH_CHAR(num);					/*事务处理标识符高8位*/\
	SendData[SendCount++] = LOW_CHAR(num);					/*事务处理标识符低8位*/\
	SendData[SendCount++] = 0x00;							/*协议标识符（MODBUS协议标识符为0x00，0x00）高8位*/\
	SendData[SendCount++] = 0x00;							/*协议标识符（MODBUS协议标识符为0x00，0x00）低8位*/\
	SendData[SendCount++] = 0x00;							/*长度域（包括单元标识符和数据域）高8位，数据包长度不确定，暂时空缺*/\
	SendData[SendCount++] = 0x00;							/*长度域（包括单元标识符和数据域）低8位，数据包长度不确定，暂时空缺*/\
	SendData[SendCount++] = ModuleAddr;						/*单元标识符*/\
	SendData[SendCount++] = Funcode;						/*功能码*/\
	SendData[SendCount++] = HIGH_CHAR(StartAddr);			/*起始地址高8位*/\
	SendData[SendCount++] = LOW_CHAR(StartAddr);			/*起始地址低8位*/\
}
/*发送请求报文*/
#define MSG_SEND	{\
	SendData[4] = HIGH_CHAR(SendCount - 6);\
	SendData[5] = LOW_CHAR(SendCount - 6);\
	if (TCP_Send(&sock, SendData, SendCount, MODBUSTCP_MASTER_List_Par.Send_MaxTime) < SendCount)\
	{\
		printf("Send modbus-tcp request msg wrong in Funcode %d\r\n", Funcode);\
		WRONG_DEAL(true);/*duan 2019/11/8 将参数值由true更为为false。如此，超时后，主站读从站的值能够保持当前值*/\
	}\
}
/*接收响应报文*/
#define MSG_RECV	{\
	if ((RecvCount = TCP_Recv(&sock, RecvData, Set_RecvCount, MODBUSTCP_MASTER_List_Par.Recv_MaxTime)) <= 0)\
	{\
		printf("Recv modbus-tcp reponse msg wrong in Funcode %d\r\n", Funcode);/**duan0517 把这段代码先注释掉*/\
		WRONG_DEAL(true);/*duan 2019/11/8 将参数值由true更为为false。如此，超时后，主站读从站的值能够保持当前值*/\
	}\
}
/*响应报文校验*/
#define RESPOND_PCK_CHECK	{\
	if(RecvData[0] != SendData[0] || RecvData[1] != SendData[1]|| RecvData[2] != SendData[2]|| RecvData[3] != SendData[3])/*判断报文头部是否一致*/\
	{\
		printf("Recv msg's head check wrong in funcode %d in module %d\r\n", Funcode, ModuleAddr);\
		WRONG_DEAL(true);\
	}\
	else if(RecvData[4] != HIGH_CHAR(Set_RecvCount - 6) || RecvData[5] != LOW_CHAR(Set_RecvCount - 6))/*判断长度信息是否正确*/\
	{\
		printf("Recv msg's length's msg check wrong in funcode %d in module %d\r\n", Funcode, ModuleAddr); \
		WRONG_DEAL(true);\
	}\
	else if (RecvData[6] != ModuleAddr)/*判断响应报文的模件地址是否正确*/\
	{\
		printf("Module address wrong in funcode %d in module %d\r\n", Funcode, ModuleAddr);\
		WRONG_DEAL(true);\
	}\
	else if ((RecvData[7] != Funcode) && ((RecvData[7] - Funcode) == 0x80))/*判断响应报文是否包含异常信息*/\
	{\
		printf("The slave station is wrong in funcode %d, the wrongcode is %d\r\n", Funcode, RecvData[8]);\
		WRONG_DEAL(true);\
	}\
	else if(RecvCount != Set_RecvCount)\
	{\
		printf("Recv PCK length wrong in funcode %d in module %d\r\n", Funcode, ModuleAddr);\
		WRONG_DEAL(true);\
	}\
}

//************************************
// Method:    	MODBUSTCP_MASTER_Funcode0x01_0x02_Work		功能码1、功能码2工作函数
// Programmer:  lww
// Time:		2019/2/27
// Returns:   	bool										true-成功；false-失败
// Parameter: 	int sock									套接字
// Parameter: 	unsigned short num							报文事务标识符（避免先发后至现象发生）
// Parameter: 	char ModuleAddr								模件地址
// Parameter: 	char Funcode								功能码
// Parameter: 	unsigned short StartAddr					起始地址
// Parameter: 	unsigned short RWNum						读写数量
// Parameter: 	int Max_WaitTime							最大超时等待时间（ms）
// Parameter: 	void * Ch									通道指针
//************************************
bool MODBUSTCP_MASTER_Funcode0x01_0x02_Work(int sock, unsigned short num, unsigned char ModuleAddr, unsigned char Funcode, unsigned short StartAddr, unsigned short RWNum, void* Ch)
{
#define REQUEST_PCK_MAXNUM	MODBUSTCP_FUNC0x01_0x02_REQUEST_PCK_MAXNUM			//< 请求报文最大长度
#define RESPOND_PCK_MAXNUM	MODBUSTCP_FUNC0x01_0x02_RESPOND_PCK_MAXNUM			//< 回复报文最大长度

	int i;
	unsigned char SendData[REQUEST_PCK_MAXNUM] = { 0 };
	unsigned char RecvData[RESPOND_PCK_MAXNUM] = { 0 };
	unsigned short SendCount = 0;
	unsigned short RecvCount = 0;
	unsigned short Set_RecvCount = 0;									//< 正确的回应报文长度

	MSG_HEAD;													//< 报文头
	SendData[SendCount++] = HIGH_CHAR(RWNum);					//< 读取数量高8位
	SendData[SendCount++] = LOW_CHAR(RWNum);					//< 读取数量低8位
	MSG_SEND;													//< 发送报文
	Set_RecvCount = 9 + RWNum / 8 + (((RWNum % 8) > 0) ? 1 : 0);//< 计算响应报文长度
	MSG_RECV;													//< 接收响应报文
	RESPOND_PCK_CHECK;											//< 响应报文校验

	for (i = 0; i < RWNum; i++) { DV_Write(&(((DVChannel_t*)Ch)[i]), ((RecvData[9 + i / 8] & (1 << (i % 8))) ? true : false), WRITE); }	//< 写入数据到数据点中
	return true;

#undef REQUEST_PCK_MAXNUM
#undef RESPOND_PCK_MAXNUM
}

//************************************
// Method:    	MODBUSTCP_MASTER_Funcode0x03_0x04_Work		功能码3、功能码4工作函数
// Programmer:  lww
// Time:		2019/2/27
// Returns:   	bool										true-成功；false-失败
// Parameter: 	int sock									套接字
// Parameter: 	unsigned short num							报文事务标识符（避免先发后至现象发生）
// Parameter: 	char ModuleAddr								模件地址
// Parameter: 	char Funcode								功能码
// Parameter: 	unsigned short StartAddr					起始地址
// Parameter: 	unsigned short RWNum						读写数量
// Parameter: 	int Max_WaitTime							最大超时等待时间（ms）
// Parameter: 	void * Ch									通道指针
// Parameter: 	bool Is_Double								是否是双字MODBUS
//************************************
bool MODBUSTCP_MASTER_Funcode0x03_0x04_Work(int sock, unsigned short num, unsigned char ModuleAddr, unsigned char Funcode, unsigned short StartAddr, unsigned short RWNum, void* Ch, bool Is_Double)
{
#define REQUEST_PCK_MAXNUM	MODBUSTCP_FUNC0x03_0x04_REQUEST_PCK_MAXNUM	//< 请求报文最大长度
#define RESPOND_PCK_MAXNUM	MODBUSTCP_FUNC0x03_0x04_RESPOND_PCK_MAXNUM	//< 回复报文最大长度

	int i;
	unsigned char SendData[REQUEST_PCK_MAXNUM] = { 0 };
	unsigned char RecvData[RESPOND_PCK_MAXNUM] = { 0 };
	unsigned short SendCount = 0;
	unsigned short RecvCount = 0;
	unsigned short Set_RecvCount = 0;									//< 正确的回应报文长度
	
 	MSG_HEAD;																			//< 报文头
	SendData[SendCount++] = HIGH_CHAR(RWNum * ((Is_Double) ? 2 : 1));					//< 读取数量高8位
	SendData[SendCount++] = LOW_CHAR(RWNum * ((Is_Double) ? 2 : 1));					//< 读取数量低8位
	MSG_SEND;																			//< 发送报文
	Set_RecvCount = 9 + 2 * RWNum * ((Is_Double) ? 2 : 1);								//< 计算响应报文长度
	MSG_RECV;																			//< 接收响应报文
	RESPOND_PCK_CHECK;																	//< 响应报文校验
	//< 写入数据到数据点中
	if (Is_Double == false)
		for (i = 0; i < RWNum; i++) { AV_Write(&(((AVChannel_t*)Ch)[i]), (float)((short)((RecvData[9 + 2 * i] << 8) + RecvData[10 + 2 * i])), WRITE); }					//< duan 20191111 修改为有符号数
	else
		for (i = 0; i < RWNum; i++)
		{
			int tmp_int;
			float tmp_float;
			tmp_int = (RecvData[9 + 4 * i] << 24) + (RecvData[10 + 4 * i] << 16) + (RecvData[11 + 4 * i] << 8) + RecvData[12 + 4 * i];
			tmp_float = *((float*)(&tmp_int));
			AV_Write(&(((AVChannel_t*)Ch)[i]), tmp_float, WRITE);
		}

	return true;
	
#undef REQUEST_PCK_MAXNUM
#undef RESPOND_PCK_MAXNUM
}

//************************************
// Method:    	MODBUSTCP_MASTER_Funcode0x05_Work			功能码5工作函数
// Programmer:  lww
// Time:		2019/2/27
// Returns:   	bool										true-成功；false-失败
// Parameter: 	int sock									套接字
// Parameter: 	unsigned short num							报文事务标识符（避免先发后至现象发生）
// Parameter: 	char ModuleAddr								模件地址
// Parameter: 	char Funcode								功能码
// Parameter: 	unsigned short StartAddr					起始地址
// Parameter: 	unsigned short RWNum						读写数量
// Parameter: 	int Max_WaitTime							最大超时等待时间（ms）
// Parameter: 	void * Ch									通道指针
//************************************
bool MODBUSTCP_MASTER_Funcode0x05_Work(int sock, unsigned short num, unsigned char ModuleAddr, unsigned char Funcode, unsigned short StartAddr, unsigned short RWNum, void* Ch)
{
#define REQUEST_PCK_MAXNUM	MODBUSTCP_FUNC0x05_REQUEST_PCK_MAXNUM			//< 请求报文最大长度
#define RESPOND_PCK_MAXNUM	MODBUSTCP_FUNC0x05_RESPOND_PCK_MAXNUM			//< 回复报文最大长度

	int i;
	unsigned char SendData[REQUEST_PCK_MAXNUM] = { 0 };
	unsigned char RecvData[RESPOND_PCK_MAXNUM] = { 0 };
	unsigned short SendCount = 0;
	unsigned short RecvCount = 0;
	unsigned short Set_RecvCount = 0;									//< 正确的回应报文长度

	MSG_HEAD;																					//< 报文头
	SendData[SendCount++] = ((((DVChannel_t*)Ch)[0].Sta_Property.CurOut_Value) ? 0xFF : 0x00);	//< 写入值高8位
	SendData[SendCount++] = 0x00;																//< 写入值低8位
	MSG_SEND;																					//< 发送报文
	Set_RecvCount = SendCount;																	//< 计算响应报文长度
	MSG_RECV;																					//< 接收响应报文
	RESPOND_PCK_CHECK;																			//< 响应报文校验

	return true;

#undef REQUEST_PCK_MAXNUM
#undef RESPOND_PCK_MAXNUM
}

//************************************
// Method:    	MODBUSTCP_MASTER_Funcode0x06_Work			功能码6工作函数
// Programmer:  lww
// Time:		2019/2/27
// Returns:   	bool										true-成功；false-失败
// Parameter: 	int sock									套接字
// Parameter: 	unsigned short num							报文事务标识符（避免先发后至现象发生）
// Parameter: 	char ModuleAddr								模件地址
// Parameter: 	char Funcode								功能码
// Parameter: 	unsigned short StartAddr					起始地址
// Parameter: 	unsigned short RWNum						读写数量
// Parameter: 	int Max_WaitTime							最大超时等待时间（ms）
// Parameter: 	void * Ch									通道指针
//************************************
bool MODBUSTCP_MASTER_Funcode0x06_Work(int sock, unsigned short num, unsigned char ModuleAddr, unsigned char Funcode, unsigned short StartAddr, unsigned short RWNum, void* Ch)
{
#define REQUEST_PCK_MAXNUM	MODBUSTCP_FUNC0x06_REQUEST_PCK_MAXNUM			//< 请求报文最大长度
#define RESPOND_PCK_MAXNUM	MODBUSTCP_FUNC0x06_RESPOND_PCK_MAXNUM			//< 回复报文最大长度

	int i;
	unsigned char SendData[REQUEST_PCK_MAXNUM] = { 0 };
	unsigned char RecvData[RESPOND_PCK_MAXNUM] = { 0 };
	unsigned short SendCount = 0;
	unsigned short RecvCount = 0;
	unsigned short Set_RecvCount = 0;									//< 正确的回应报文长度
	
	MSG_HEAD;													//< 报文头
	unsigned short tmp_short;
	tmp_short = (unsigned short)((AVChannel_t*)Ch)[0].Sta_Property.CurOut_Value;
	SendData[SendCount++] = HIGH_CHAR(tmp_short);				//< 写入值高8位
	SendData[SendCount++] = LOW_CHAR(tmp_short);				//< 写入值低8位
	MSG_SEND;													//< 发送报文
	Set_RecvCount = SendCount;									//< 计算响应报文长度
	MSG_RECV;													//< 接收响应报文
	RESPOND_PCK_CHECK;											//< 响应报文校验

	return true;

#undef REQUEST_PCK_MAXNUM
#undef RESPOND_PCK_MAXNUM
}

//************************************
// Method:    	MODBUSTCP_MASTER_Funcode0x0F_Work			功能码15工作函数
// Programmer:  lww
// Time:		2019/2/27
// Returns:   	bool										true-成功；false-失败
// Parameter: 	int sock									套接字
// Parameter: 	unsigned short num							报文事务标识符（避免先发后至现象发生）
// Parameter: 	char ModuleAddr								模件地址
// Parameter: 	char Funcode								功能码
// Parameter: 	unsigned short StartAddr					起始地址
// Parameter: 	unsigned short RWNum						读写数量
// Parameter: 	int Max_WaitTime							最大超时等待时间（ms）
// Parameter: 	void * Ch									通道指针
//************************************
bool MODBUSTCP_MASTER_Funcode0x0F_Work(int sock, unsigned short num, unsigned char ModuleAddr, unsigned char Funcode, unsigned short StartAddr, unsigned short RWNum, void* Ch)
{
#define REQUEST_PCK_MAXNUM	MODBUSTCP_FUNC0x0F_REQUEST_PCK_MAXNUM			//< 请求报文最大长度
#define RESPOND_PCK_MAXNUM	MODBUSTCP_FUNC0x0F_RESPOND_PCK_MAXNUM			//< 回复报文最大长度

	int i;
	unsigned char SendData[REQUEST_PCK_MAXNUM] = { 0 };
	unsigned char RecvData[RESPOND_PCK_MAXNUM] = { 0 };
	unsigned short SendCount = 0;
	unsigned short RecvCount = 0;
	unsigned short Set_RecvCount = 0;									//< 正确的回应报文长度

	MSG_HEAD;															//< 报文头
	SendData[SendCount++] = HIGH_CHAR(RWNum);							//< 写入数量高8位
	SendData[SendCount++] = LOW_CHAR(RWNum);							//< 写入数量低8位
	SendData[SendCount++] = (unsigned char)(RWNum / 8 + (((RWNum % 8) > 0) ? 1 : 0));	//< 写入的字节数
	//写输出值
	for (i = 0; i < RWNum; i++) { SendData[SendCount + i / 8] = (unsigned char)(SendData[SendCount + i / 8] + ((((DVChannel_t*)Ch)[i].Sta_Property.CurOut_Value) << (i % 8))); }
	SendCount += (i / 8 + 1);
	MSG_SEND;															//< 发送报文
	Set_RecvCount = RESPOND_PCK_MAXNUM;									//< 计算响应报文长度
	MSG_RECV;															//< 接收响应报文
	RESPOND_PCK_CHECK;													//< 响应报文校验

	return true;

#undef REQUEST_PCK_MAXNUM
#undef RESPOND_PCK_MAXNUM
}

//************************************
// Method:    	MODBUSTCP_MASTER_Funcode0x10_Work			功能码16工作函数
// Programmer:  lww
// Time:		2019/2/27
// Returns:   	bool										true-成功；false-失败
// Parameter: 	int sock									套接字
// Parameter: 	unsigned short num							报文事务标识符（避免先发后至现象发生）
// Parameter: 	char ModuleAddr								模件地址
// Parameter: 	char Funcode								功能码
// Parameter: 	unsigned short StartAddr					起始地址
// Parameter: 	unsigned short RWNum						读写数量
// Parameter: 	int Max_WaitTime							最大超时等待时间（ms）
// Parameter: 	void * Ch									通道指针
// Parameter: 	bool Is_Double								是否是双字MODBUS
//************************************
bool MODBUSTCP_MASTER_Funcode0x10_Work(int sock, unsigned short num, unsigned char ModuleAddr, unsigned char Funcode, unsigned short StartAddr, unsigned short RWNum, void* Ch, bool Is_Double)
{
#define REQUEST_PCK_MAXNUM	MODBUSTCP_FUNC0x10_REQUEST_PCK_MAXNUM			//< 请求报文最大长度
#define RESPOND_PCK_MAXNUM	MODBUSTCP_FUNC0x10_RESPOND_PCK_MAXNUM			//< 回复报文最大长度

	int i;
	unsigned char SendData[REQUEST_PCK_MAXNUM] = { 0 };
	unsigned char RecvData[RESPOND_PCK_MAXNUM] = { 0 };
	unsigned short SendCount = 0;
	unsigned short RecvCount = 0;
	unsigned short Set_RecvCount = 0;									//< 正确的回应报文长度

	MSG_HEAD;																			//< 报文头
	SendData[SendCount++] = HIGH_CHAR(RWNum * ((Is_Double) ? 2 : 1));					//< 读取数量高8位
	SendData[SendCount++] = LOW_CHAR(RWNum * ((Is_Double) ? 2 : 1));					//< 读取数量低8位
	SendData[SendCount++] = (unsigned char)(2 * RWNum * ((Is_Double) ? 2 : 1));			//< 写入的字节数
	if (Is_Double == false)
		for (i = 0; i < RWNum; i++)//写寄存器值
		{
			short tmp_short;
			tmp_short = (short)((AVChannel_t*)Ch)[i].Sta_Property.CurOut_Value;
			SendData[SendCount + 2 * i] = HIGH_CHAR(tmp_short);
			SendData[SendCount + 2 * i + 1] = LOW_CHAR(tmp_short);
		}
	else
		for (i = 0; i < RWNum; i++)
		{
			int tmp_int;
			tmp_int = *((int*)(&((AVChannel_t*)Ch)[i].Sta_Property.CurOut_Value));
			SendData[SendCount + 4 * i] = (unsigned char)((tmp_int >> 24) & 0xFF);
			SendData[SendCount + 4 * i + 1] = (unsigned char)((tmp_int >> 16) & 0xFF);
			SendData[SendCount + 4 * i + 2] = (unsigned char)((tmp_int >> 8) & 0xFF);
			SendData[SendCount + 4 * i + 3] = (unsigned char)(tmp_int & 0xFF);
		}
	SendCount += (int)(2 * RWNum * ((Is_Double) ? 2 : 1));
	MSG_SEND;													//< 发送报文
	Set_RecvCount = RESPOND_PCK_MAXNUM;							//< 计算响应报文长度
	MSG_RECV;													//< 接收响应报文
	RESPOND_PCK_CHECK;											//< 响应报文校验

	return true;

#undef REQUEST_PCK_MAXNUM
#undef RESPOND_PCK_MAXNUM
}
#undef WRONG_DEAL
#undef MSG_HEAD
#undef MSG_SEND
#undef MSG_RECV
#undef RESPOND_PCK_CHECK


//************************************
// Method:    	CHANGE_CARD_LIST_PAR		修改该类型卡件属性
// Programmer:  lww
// Time:		2019/4/4
// Returns:   	int							读取字节长度计数值
// Parameter: 	Card_Base_t* arg			指定卡件属性结构体的指针
// Parameter: 	void** Data					存放数据包当前指针位置的地址
//************************************
int CHANGE_CARD_LIST_PAR(MODBUSTCP_MASTER)(Card_Base_t* arg, void** Data)
{
	int _iLen = 0;
	MEMREAD((*CLIST_PAR(MODBUSTCP_MASTER)), Data[0]);
	return _iLen;
}

//************************************
// Method:    	CHANGE_CARD_PAR				在线修改卡件参数函数
// Programmer:  lww
// Time:		2018/11/16
// Returns:   	int							读取字节长度计数值
// Parameter: 	Card_Base_t* arg			指定卡件属性结构体的指针
// Parameter: 	void** Data					存放数据包当前指针位置的地址
//************************************
int CHANGE_CARD_PAR(MODBUSTCP_MASTER)(Card_Base_t* arg, void** Data)
{
	int _iLen = 0;
	MEMREAD(((NAME(MODBUSTCP_MASTER)*)arg)->Par, Data[0]);
	return _iLen;
}


//************************************
// Method:    	INIT_STAPAR					初始化卡件不可调参数结构体
// Programmer:  lww
// Time:		2018/11/16
// Returns:   	int							读取字节长度计数值
// Parameter: 	Card_Base_t* arg			指定卡件属性结构体的指针
// Parameter: 	void** Data					存放数据包当前指针位置的地址
//************************************
int INIT_CARD_STA(MODBUSTCP_MASTER)(Card_Base_t* arg, void** Data)
{
	int _iLen = 0;
	MEMREAD(((NAME(MODBUSTCP_MASTER)*)arg)->Sta, Data[0]);
	return _iLen;
}
